home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / DYN401.ZIP / threads / thread.d < prev    next >
Text File  |  1996-02-04  |  17KB  |  833 lines

  1.  
  2.  
  3.  
  4.  
  5. /*
  6.  *
  7.  *    Copyright (c) 1993-1996 Algorithms Corporation
  8.  *    3020 Liberty Hills Drive
  9.  *    Franklin, TN  37067
  10.  *
  11.  *    ALL RIGHTS RESERVED.
  12.  *
  13.  *
  14.  *
  15.  */
  16.  
  17.  
  18. #include <string.h>
  19.  
  20. #ifndef    unix
  21. #include <conio.h>
  22. #else
  23. int    getch(void);
  24. int    kbhit(void);
  25. #endif
  26.  
  27.  
  28. typedef    struct    _priority_queue      *PQ;
  29.  
  30.  
  31.  
  32. defclass  Thread  {
  33.     object        iObj;        /*  pointer to thread object  */
  34.     char        *iName;
  35.     int        (*iFun)(void *);
  36.     jmp_buf        iRtn;
  37.     char        *iStack_buf;    /*  save buffer for thread stack  */
  38.     char        *iStack_location;  /*  ending real stack position  */
  39.     int        iStack_buf_size;/*  size of stack_buf        */
  40.     int        iStack_size;    /*  space used on stack_buf    */
  41.     int        iState;        /*  current state of thread    */
  42.     int        iAutoDispose;    /*  dispose when thread done    */
  43.     int        iPriority;    /*  thread priority        */
  44.     void        *iArg;        /*  argument to thread        */
  45.     int        iPrev_state;    /*  state prior to a hold    */
  46.     int        iHold_count;    /*  number of times put on hold */
  47.     int        iRtnVal;
  48.     int        iWr;        /*  wait return            */
  49.     object        iWait;        /*  LinkObject of threads waiting for done    */
  50.     struct _Thread_iv_t *iTwait;    /*  thread this thread is waiting for */
  51.     struct _Thread_iv_t *iNext, *iPrev;/*  thread queue        */
  52.     object        iSema;        /*  semaphore waiting for    */
  53. /*    void        *iKmrp;        /*  kernel memory range pointer */
  54.  
  55.  class:
  56.     char    *cTs_stkpos;    /*  thread starting stack position    */
  57.  
  58.     PQ    cMpq;        /*  master priority queue        */
  59.     PQ    cCpq;        /*  current priority queue executing    */
  60.     ivType    *cCt;        /*  current executing thread        */
  61.  
  62.     ivType    *cTnr;        /*  list of threads not running        */
  63.  
  64.     ivType    *cGkt;        /*  blocking getkey thread        */
  65.  
  66.     PQ    cFpql;        /*  free priority queue list        */
  67.  
  68.     object    cThreads;    /*  StringDictionary of threads - also used
  69.                     to prevent GC from collecting threads */
  70.     unsigned long    cThrno;    /*  thread number - for thread name generation */
  71.  
  72.  init:    init_class;
  73. };
  74.  
  75.  
  76. struct    _priority_queue  {
  77.     int    priority;    /*  larger numbers are higher prioritys */
  78.     ivType    *thread;    /*  queue of threads at this priority */
  79.     PQ    next;       /*  next lower priority queue  */
  80. };
  81.  
  82.  
  83.  
  84. jmp_buf    _t_start;    /*  thread startup location        */
  85.  
  86.  
  87.  
  88. #define STACKINC    100  /*  stack increment size  */
  89.     
  90.  
  91.  
  92. #define NTICKS    1
  93.  
  94. static    objrtn    Release(object self, int yld);
  95.  
  96. #ifdef    FUNCTIONS
  97.  
  98. #define NEXT_THREAD    next_thread()
  99.  
  100. static    void next_thread(void);
  101. static    void add_tnr(ivType *t);
  102. static    void del_tnr(ivType *t);
  103.  
  104. #else
  105.  
  106. #define NEXT_THREAD            \
  107.     if (cCpq)            \
  108.         cCpq->thread = cCpq->thread->iNext;\
  109.     if (cGkt  &&  kbhit())  {    \
  110.         Release(cGkt->iObj, 0);    \
  111.         cGkt = NULL;        \
  112.     }                \
  113.     if (cCpq = cMpq)        \
  114.         cCt = cCpq->thread;    \
  115.     else                \
  116.         exit(0)        /*  no ready threads  */
  117.  
  118. #define add_tnr(t)            \
  119.     if (t->iNext = cTnr)        \
  120.         cTnr->iPrev = t;    \
  121.     t->iPrev = NULL;        \
  122.     cTnr = t
  123.  
  124. #define del_tnr(t)            \
  125.     if (t->iPrev)            \
  126.         t->iPrev->iNext = t->iNext;\
  127.     else                \
  128.         cTnr = t->iNext;    \
  129.     if (t->iNext)            \
  130.         t->iNext->iPrev = t->iPrev
  131.  
  132. #endif
  133.  
  134. extern    void    _start_timer(void);
  135.  
  136.  
  137. static    void start_thread(ivType *s);
  138. static    void stop_thread(ivType *t);
  139. static    void resolve_waits(ivType *t);
  140. static    void delete_wait(ivType *t);
  141. static    PQ new_pq(void);
  142. static    void free_pq(PQ t);
  143. static    void delete_sema_waits(ivType *t);
  144. static    void _dynace_yield(void);
  145. static  char *strsave(char *);
  146.  
  147. #ifdef    FUNCTIONS
  148.  
  149. static    void    next_thread(void)
  150. {
  151.     if (cCpq)
  152.         cCpq->thread = cCpq->thread->iNext;
  153.     if (cGkt  &&  kbhit())  {
  154.         Release(cGkt->iObj, 0);
  155.         cGkt = NULL;
  156.     }
  157.     if (cCpq = cMpq)
  158.         cCt = cCpq->thread;
  159.     else
  160.         exit(0);    /*  no ready threads  */
  161. }
  162.  
  163. #endif
  164.  
  165. /*  start_thread takes a thread and puts it in the running threads priority
  166.     queue    */
  167.  
  168. static    void    start_thread(ivType *s)
  169. {
  170.     PQ    tpq, ppq, npq;
  171.  
  172.     for (ppq=NULL, tpq=cMpq ; tpq && s->iPriority < tpq->priority ; ppq=tpq, tpq=tpq->next);
  173.     if (!tpq  ||  s->iPriority != tpq->priority)  {
  174.         npq = new_pq();
  175.         s->iNext = s->iPrev = s;
  176.         npq->priority = s->iPriority;
  177.         npq->thread = s;
  178.         npq->next = tpq;
  179.         if (ppq)
  180.             ppq->next = npq;
  181.         else
  182.             cMpq = npq;
  183.     } else 
  184.         if (tpq == cCpq)  {
  185.             s->iNext = tpq->thread->iNext;
  186.             s->iPrev = tpq->thread;
  187.             tpq->thread->iNext = s;
  188.             s->iNext->iPrev = s;
  189.         } else {
  190.             s->iNext = tpq->thread;
  191.             s->iPrev = tpq->thread->iPrev;
  192.             tpq->thread->iPrev = s;
  193.             s->iPrev->iNext = s;
  194.             tpq->thread = s;
  195.         }
  196. }
  197.         
  198. /*  stop_thread takes a thread off the running threads priority queue  */
  199.  
  200. static    void    stop_thread(ivType *t)
  201. {
  202.     PQ    pq, ppq;
  203.  
  204.     for (ppq=NULL, pq=cMpq ; pq  &&  pq->priority != t->iPriority ;
  205.          ppq=pq, pq=pq->next);
  206.     if (!pq)
  207.         goto error;
  208.     if (t->iNext != t)  {
  209.         t->iPrev->iNext = t->iNext;
  210.         t->iNext->iPrev = t->iPrev;
  211.         if (pq->thread == t)  {
  212.             pq->thread = t->iNext;
  213.             if (pq == cCpq)
  214.                 cCpq = NULL;
  215.         }
  216.     }  else  {
  217.         if (pq->thread != t)
  218.             goto error;
  219.         if (pq == cCpq)
  220.             cCpq = NULL;
  221.         if (ppq)
  222.             ppq->next = pq->next;
  223.         else
  224.             cMpq = pq->next;
  225.         free_pq(pq);
  226.     }
  227.     return;
  228.  error:
  229.     fprintf(stderr, "Bad priority queue\n");
  230.     exit(1);
  231. }
  232.         
  233. #ifdef    FUNCTIONS
  234.  
  235. /*  add thread to the threads-not-running list   */
  236.  
  237. static    void    add_tnr(ivType *t)
  238. {
  239.     if (t->iNext = cTnr)
  240.         cTnr->iPrev = t;
  241.     t->iPrev = NULL;
  242.     cTnr = t;
  243. }
  244.  
  245. /*  delete thread from the threads-not-running list   */
  246.  
  247. static    void    del_tnr(ivType *t)
  248. {
  249.     if (t->iPrev)
  250.         t->iPrev->iNext = t->iNext;
  251.     else
  252.         cTnr = t->iNext;
  253.     if (t->iNext)
  254.         t->iNext->iPrev = t->iPrev;
  255. }
  256.  
  257. #endif
  258.  
  259. imeth    gKill : Kill (object self, int rtn)
  260. {
  261.     if (iState == DONE_THREAD)
  262.         return self;
  263.     INHIBIT_THREADER;
  264.     iRtnVal = rtn;
  265.     if (iStack_buf)  {
  266.         free(iStack_buf);
  267.         iStack_buf = NULL;
  268.         iStack_buf_size = iStack_size = 0;
  269.     }
  270.     if (iState == NEW_THREAD  ||  iState == RUNNING_THREAD)  {
  271.         stop_thread(iv);
  272.         add_tnr(iv);
  273.     } else if (iState == WAITING_FOR_THREAD)
  274.         delete_wait(iv);
  275.     iState = DONE_THREAD;
  276.     if (iSema)
  277.         delete_sema_waits(iv);
  278.     if (iWait)
  279.         resolve_waits(iv);
  280.     if (iv == cGkt)
  281.         cGkt = NULL;
  282. #if 0
  283.     if (iKmrp)  {
  284.         static    gRemoveRegisteredMemory_t    rrm = NULL;
  285.  
  286.         if (!rrm)
  287.             rrm = cmcPointer(Dynace, gRemoveRegisteredMemory);
  288.         (rrm)(Dynace, iKmrp);
  289.         iKmrp = NULL;
  290.     }
  291. #endif
  292.     ENABLE_THREADER;
  293.     if (!cCpq  ||  cCt == iv)  {
  294.         cCt = NULL;
  295.         _dynace_yield();
  296.     }
  297.     return self;
  298. }
  299.  
  300. imeth    object    gDispose, gDeepDispose : Dispose (object self)
  301. {
  302.     INHIBIT_THREADER;
  303.     if (iStack_buf)
  304.         free(iStack_buf);
  305.     if (iState == NEW_THREAD  ||  iState == RUNNING_THREAD)
  306.         stop_thread(iv);
  307.     else  {
  308.         if (iState == WAITING_FOR_THREAD)
  309.             delete_wait(iv);
  310.         del_tnr(iv);
  311.     }
  312. /*    iRtnVal = r;  */
  313.     iState = DONE_THREAD;
  314.     if (iSema)
  315.         delete_sema_waits(iv);
  316.     if (iWait)  {
  317.         static    gDispose_t    dispose = NULL;
  318.  
  319.         if (!dispose)
  320.             dispose = imcPointer(LinkObject, gDispose);
  321.         resolve_waits(iv);
  322.         (*dispose)(iWait);
  323.     }
  324.     if (iv == cGkt)
  325.         cGkt = NULL;
  326. #if 0
  327.     if (iKmrp)  {
  328.         static    gRemoveRegisteredMemory_t    rrm = NULL;
  329.  
  330.         if (!rrm)
  331.             rrm = cmcPointer(Dynace, gRemoveRegisteredMemory);
  332.         (*rrm)(Dynace, iKmrp);
  333.     }
  334. #endif
  335.     gRemoveStr(cThreads, iName);
  336.     free(iName);
  337.     gDispose(super);
  338.     ENABLE_THREADER;
  339.     if (!cCpq  ||  cCt == iv)  {
  340.         cCt = NULL;
  341.         _dynace_yield();
  342.     }
  343.     return NULL;
  344. }
  345.  
  346. static    char    *strsave(char *s)
  347. {
  348.     char    *p = Tnalloc(char, strlen(s)+1);
  349.     strcpy(p, s);
  350.     return p;
  351. }
  352.  
  353. cmeth    gNew()
  354. {
  355.     return gShouldNotImplement(self, "gNew");
  356. }
  357.  
  358. cmeth    gNewThread, <vNew> (object self, char *name, ifun fun, int priority, void *arg, int run, int autoDispose)
  359. {
  360.     char    buf[30];
  361.     object    obj = gNew(super);
  362.     ivType    *iv = ivPtr(obj);
  363.     static    gFindStr_t    find = NULL;
  364.     static    gAddStr_t    add = NULL;
  365.  
  366.     INHIBIT_THREADER;
  367.     iObj = obj;
  368.     if (name)
  369.         iName = strsave(name);
  370.     else  {
  371.         sprintf(buf, "unnamed-%ld", ++cThrno);
  372.         iName = strsave(buf);
  373.     }
  374.     if (!find)
  375.         find = imcPointer(StringDictionary, gFindStr);
  376.     if ((*find)(cThreads, iName))  {
  377.         free(iName);
  378.         gDispose(super);
  379.         ENABLE_THREADER;
  380.         return NULL;
  381.     }
  382.         
  383.     iFun = (int (*)(void *)) fun;
  384.     iPriority = priority;
  385.     iArg = arg;
  386.     iAutoDispose = autoDispose;
  387.  
  388.     if (!add)
  389.         add = imcPointer(StringDictionary, gAddStr);
  390.     (*add)(cThreads, iName, obj);
  391.     ENABLE_THREADER;
  392.  
  393.     if (run)  {
  394.         iState = NEW_THREAD;
  395.         start_thread(iv);
  396.         if (cCt  &&  cCt->iPriority < priority)
  397.             _dynace_yield();
  398.     }  else  {
  399.         iPrev_state = NEW_THREAD;
  400.         iState = HOLD_THREAD;
  401.         iHold_count = 1;
  402.         add_tnr(iv);
  403.     }
  404.  
  405.     return obj;
  406. }
  407.  
  408. void    _start_threader(char *stkpos)
  409. {
  410.     object    t;
  411.  
  412.     Thread;
  413.     if (cMpq)
  414.         return;
  415.  
  416.     INHIBIT_THREADER;
  417.     t = gNewThread(CLASS, "main", NULL, DEFAULT_PRIORITY, NULL, 1, 0);
  418.     ENABLE_THREADER;
  419.     cCt = ivPtr(t);
  420.  
  421.     cCt->iState = RUNNING_THREAD;
  422.     cCpq = cMpq;
  423.  
  424.     cTs_stkpos = stkpos;
  425.  
  426.     _start_timer();
  427. }
  428.  
  429. void    _start_thread(void)
  430. {
  431.     cCt->iState = RUNNING_THREAD;
  432.     _tick_count = NTICKS;
  433.     cCt->iRtnVal = (*cCt->iFun)(cCt->iArg);
  434.     Kill(cCt->iObj, cCt->iRtnVal);
  435.     if (cCt->iAutoDispose)  
  436.         Dispose(cCt->iObj);
  437. }
  438.  
  439. imeth    gHold : Hold (object self)
  440. {
  441.     if (iState == DONE_THREAD)
  442.         return self;
  443.     if (iState == HOLD_THREAD)  {
  444.         iHold_count++;
  445.         return self;
  446.     }
  447.     if (iState == NEW_THREAD  ||  iState == RUNNING_THREAD)  {
  448.         stop_thread(iv);
  449.         add_tnr(iv);
  450.     }
  451.     iPrev_state = iState;
  452.     iState = HOLD_THREAD;
  453.     iHold_count = 1;
  454.     if (iv == cCt)
  455.         _dynace_yield();
  456.     return self;
  457. }
  458.  
  459. imeth    gRelease : Release (object self, int yld)
  460. {
  461.     if (iState == HOLD_THREAD  &&  !--iHold_count)  {
  462.         iState = iPrev_state;
  463.         if (iState == NEW_THREAD  ||  iState == RUNNING_THREAD)  {
  464.             del_tnr(iv);
  465.             start_thread(iv);
  466.             if (yld  &&  iPriority > cCt->iPriority)
  467.                 _dynace_yield();
  468.         }
  469.     }
  470.     return self;
  471. }
  472.  
  473. static    void    _dynace_yield(void)
  474. {
  475.     ivType    *t;
  476.  
  477.     /*  save current thread stack  */
  478.  
  479.     if (cCt  &&  cCt->iState != DONE_THREAD)  {
  480. #ifdef sparc
  481.         /* save current stack frame (approximately 0x70 byte), too */
  482.         cCt->iStack_location = (char *) &t - 0x80;
  483. #else
  484.         cCt->iStack_location = (char *) &t;
  485. #endif
  486.         if ((cCt->iStack_size = cTs_stkpos - cCt->iStack_location) < 0)
  487.             cCt->iStack_size = 0;
  488.         if (cCt->iStack_size > cCt->iStack_buf_size)  {
  489.             cCt->iStack_buf_size = ((cCt->iStack_size / STACKINC) + 1) * STACKINC;
  490.             if (cCt->iStack_buf)
  491.                 cCt->iStack_buf = Tnrealloc(char, cCt->iStack_buf_size, cCt->iStack_buf);
  492.             else
  493.                 cCt->iStack_buf = Tnalloc(char, cCt->iStack_buf_size);
  494. #if 0
  495.             {
  496.                 static    gChangeRegisteredMemory_t crm=NULL;
  497.                 static    gRegisterMemory_t      rm;
  498.  
  499.                 if (!crm)  {
  500.                     INHIBIT_THREADER;
  501.                     crm = cmcPointer(Dynace, gChangeRegisteredMemory);
  502.                     rm = cmcPointer(Dynace, gRegisterMemory);
  503.                     ENABLE_THREADER;
  504.                 }
  505.                 if (cCt->iKmrp)
  506.                     (*crm)(Dynace, cCt->iKmrp, cCt->iStack_buf, (long) cCt->iStack_buf_size);
  507.                 else
  508.                     cCt->iKmrp = (void *)(*rm)(Dynace, cCt->iStack_buf, (long) cCt->iStack_buf_size);
  509.             }
  510. #endif
  511.         }
  512.         if (cCt->iStack_size)  {
  513. #ifdef sparc
  514.             asm("t 3");    /* flush out registers */
  515. #endif
  516.             memcpy(cCt->iStack_buf, cCt->iStack_location, cCt->iStack_size);
  517.         }
  518.  
  519.         /*  save return address  */
  520.  
  521.         if (setjmp(cCt->iRtn))  {
  522.  
  523.             /*  restore & resume thread  */
  524.  
  525.             if (cCt->iStack_size)
  526.                 memcpy(cCt->iStack_location, cCt->iStack_buf, cCt->iStack_size);
  527.             _tick_count = NTICKS;
  528.             return;    
  529.         }
  530.     }
  531.  
  532.     /*  choose next thread  */
  533.  
  534.     NEXT_THREAD;
  535.  
  536.     if (cCt->iState == NEW_THREAD)
  537.         longjmp(_t_start, 1);
  538.     else  {
  539. #ifdef sparc
  540.         if (cCt->iStack_size){
  541.             asm("t 3");    /*  flush out registers */
  542.             memcpy(cCt->iStack_location, cCt->iStack_buf, cCt->iStack_size);
  543.         }
  544. #endif
  545.         longjmp(cCt->iRtn, 1);
  546.     }
  547. }
  548.  
  549. cmeth    gFindStr, <vFind> (object self, char *name)
  550. {
  551.     USE(self);
  552.     return name ? gFindValueStr(cThreads, name) : (cCt ? cCt->iObj : (object) NULL);
  553. #if 0
  554.     ivType    *t, *s;
  555.     PQ    pq;
  556.  
  557.     if (!name)
  558.         return cCt ? cCt->iObj : NULL;
  559.     for (pq=cMpq ; pq ; pq=pq->next)  {
  560.         s = t = pq->thread;
  561.         do  {
  562.             if (t->iName  &&  !strcmp(t->iName, name))
  563.                 return t->iObj;
  564.             t = t->iNext;
  565.         } while (t != s);
  566.     }
  567.     for (t=cTnr ; t ; t=t->iNext)
  568.         if (t->iName  &&  !strcmp(t->iName, name))
  569.             return t->iObj;
  570.     return NULL;
  571. #endif
  572. }
  573.  
  574. imeth    int    gIntValue(object self)
  575. {
  576.     return iRtnVal;
  577. }
  578.  
  579. imeth    int    gState(object self)
  580. {
  581.     return iState;
  582. }
  583.  
  584. imeth    char    *gName(object self)
  585. {
  586.     return iName;
  587. }
  588.  
  589. imeth    int    gPriority(object self)
  590. {
  591.     return iPriority;
  592. }
  593.  
  594. imeth    gChangePriority(object self, int p)
  595. {
  596.     int    f, oldp;
  597.  
  598.     oldp = iPriority;
  599.     if (f = iState == NEW_THREAD  ||  iState == RUNNING_THREAD)
  600.         stop_thread(iv);
  601.     iPriority = p;
  602.     if (f)
  603.         start_thread(iv);
  604.     if (cCt == iv  &&  p < oldp  &&  cMpq->thread->iPriority > p  ||
  605.         cCt != iv  &&  f  &&  p > cCt->iPriority)
  606.         _dynace_yield();
  607.     return self;
  608. }
  609.  
  610. imeth    int    gWaitFor(object self)
  611. {
  612.     if (iv == cCt)
  613.         return 0;
  614.     if (iState != DONE_THREAD)  {
  615.         stop_thread(cCt);
  616.         add_tnr(cCt);
  617.  
  618.         INHIBIT_THREADER;
  619.         if (!iWait)
  620.             iWait = gNew(LinkObject);
  621.         gAddFirst(iWait, cCt->iObj);
  622.         ENABLE_THREADER;
  623.  
  624.         cCt->iTwait = iv;
  625.         cCt->iState = WAITING_FOR_THREAD;
  626.         _dynace_yield();
  627.         return cCt->iWr;
  628.     } else
  629.         return iRtnVal;
  630. }
  631.  
  632. /*  this function signals all the threads waiting for t (used when t is DONE) */
  633.  
  634. static    void    resolve_waits(ivType *t)
  635. {
  636.     object    thread;
  637.     static    gFirst_t    first=NULL;
  638.     static    gDisposeFirst_t    disposeFirst;
  639.  
  640.     if (!t->iWait)
  641.         return;
  642.     INHIBIT_THREADER;
  643.     if (!first)  {
  644.         first = imcPointer(LinkObject, gFirst);
  645.         disposeFirst = imcPointer(LinkObject, gDisposeFirst);
  646.     }
  647.     while (thread = (*first)(t->iWait))  {
  648.         ivType    *tt;
  649.  
  650.         tt = ivPtr(thread);
  651.         tt->iState = RUNNING_THREAD;
  652.         del_tnr(tt);
  653.         start_thread(tt);
  654.         tt->iWr = t->iRtnVal;
  655.         t->iTwait = NULL;
  656.         (*disposeFirst)(t->iWait);
  657.     }
  658.     ENABLE_THREADER;
  659. }
  660.  
  661. /*  this functions is used to tell other threads that thread t is no longer
  662.     waiting  */
  663.  
  664. static    void    delete_wait(ivType *t)
  665. {
  666.     object    linkSequence, linkValue, thread;
  667.     static    gDispose_t    disposeNode, dispose;
  668.     static    gValue_t    value;
  669.     static    gNext_t    next;
  670.     static    gSequenceLinks_t    sequenceLinks = NULL;
  671.  
  672.     if (!t->iTwait->iWait)
  673.         return;
  674.     INHIBIT_THREADER;
  675.     if (!sequenceLinks)  {
  676.         sequenceLinks = imcPointer(LinkObject, gSequenceLinks);
  677.         next = imcPointer(LinkSequence, gNext);
  678.         value = imcPointer(LinkValue, gValue);
  679.         disposeNode = imcPointer(LinkValue, gDispose);
  680.         dispose = imcPointer(LinkSequence, gDispose);
  681.     }
  682.     linkSequence = (*sequenceLinks)(t->iTwait->iWait);
  683.     while (linkValue = (*next)(linkSequence))  {
  684.         thread = (*value)(linkValue);
  685.         if (thread == t->iObj)  {
  686.             (*disposeNode)(linkValue);
  687.             break;
  688.         }
  689.     }
  690.     if (linkValue)
  691.         (*dispose)(linkSequence);
  692.     ENABLE_THREADER;
  693. }
  694.  
  695. static    PQ    new_pq(void)
  696. {
  697.     PQ    t;
  698.  
  699.     if (cFpql)  {
  700.         t = cFpql;
  701.         cFpql = t->next;
  702.         memset(t, 0, sizeof(*t));
  703.     }  else
  704.         t = Tcalloc(struct _priority_queue);
  705.     return(t);
  706. }
  707.  
  708. static    void    free_pq(PQ t)
  709. {
  710.     t->next = cFpql;
  711.     cFpql = t;
  712. }
  713.  
  714. static    void    delete_sema_waits(ivType *t)
  715. {
  716.     static    gRemoveWaits_t    removeWaits = NULL;
  717.  
  718.     INHIBIT_THREADER;
  719.     if (!removeWaits)
  720.         removeWaits = imiPointer(t->iSema, gRemoveWaits);
  721.     (*removeWaits)(t->iSema, t->iObj);
  722.     t->iSema = NULL;
  723.     ENABLE_THREADER;
  724. }
  725.  
  726. cmeth    int    gBlockingGetkey(object self)
  727. {
  728.     USE(self);
  729.     if (cGkt)
  730.         return -1;
  731.     if (!kbhit())  {
  732.         cGkt = cCt;
  733.         Hold(cCt->iObj);
  734.     }
  735.     return getch();
  736. }
  737.  
  738. /*  the following method is used as a subroutine by Semaphore Class  */
  739.  
  740. imeth    gReleaseSemaphore(object self)
  741. {
  742.     if (iState == WAITING_FOR_SEMAPHORE)  {
  743.         iState = RUNNING_THREAD;
  744.         del_tnr(iv);
  745.         start_thread(iv);
  746.     } else if (iState == HOLD_THREAD  &&  iPrev_state == WAITING_FOR_SEMAPHORE)
  747.         iPrev_state = RUNNING_THREAD;
  748.     iSema = NULL;
  749.     return self;
  750. }
  751.  
  752. /*  the following method is used as a subroutine by Semaphore Class  */
  753.  
  754. imeth    gWaitSemaphore(object self, object sema)
  755. {
  756.     stop_thread(iv);
  757.     add_tnr(iv);
  758.     iState = WAITING_FOR_SEMAPHORE;
  759.     iSema = sema;
  760.     return self;
  761. }
  762.  
  763. static    objrtn    MarkThreadStacks(object self)
  764. {
  765.     ivType    *t, *s;
  766.     PQ    pq;
  767.     static    gMarkRange_t    markRange = NULL;
  768.  
  769.     if (!markRange)
  770.         markRange = cmcPointer(Dynace, gMarkRange);
  771.  
  772.     for (pq=cMpq ; pq ; pq=pq->next)  {
  773.         s = t = pq->thread;
  774.         do  {
  775.             if (t->iStack_buf  &&  t->iStack_size)
  776.                 (*markRange)(Dynace, (char _HUGE **)t->iStack_buf, (char _HUGE **)(t->iStack_buf + t->iStack_size));
  777.             t = t->iNext;
  778.         } while (t != s);
  779.     }
  780.     for (t=cTnr ; t ; t=t->iNext)
  781.         if (t->iStack_buf  &&  t->iStack_size)
  782.             (*markRange)(Dynace, (char _HUGE **) t->iStack_buf, (char _HUGE **)(t->iStack_buf + t->iStack_size));
  783.     return self;
  784. }
  785.  
  786. #ifdef unix
  787.  
  788. /*  not implemented yet on unix.  */
  789.  
  790. int    kbhit(void)
  791. {
  792.     return 0;
  793. }
  794.  
  795. int    getch(void)
  796. {
  797.     return getchar();
  798. }
  799.  
  800. #endif
  801.  
  802. imeth    gCopy, gDeepCopy (object self)
  803. {
  804.     return gShouldNotImplement(self, "Copy/DeepCopy");
  805. }
  806.  
  807. static    void    init_class(void)
  808. {
  809.  
  810. /*    gDontCollect(CLASS);    */
  811.  
  812.     __dynace_yield = _dynace_yield;
  813.  
  814.     cThreads = gNewWithInt(StringDictionary, 41);
  815.  
  816.     gMarkingMethod(CLASS, (ofun) MarkThreadStacks);
  817. }
  818.  
  819.  
  820. /*
  821.  *
  822.  *    Copyright (c) 1993-1996 Algorithms Corporation
  823.  *    3020 Liberty Hills Drive
  824.  *    Franklin, TN  37067
  825.  *
  826.  *    ALL RIGHTS RESERVED.
  827.  *
  828.  *
  829.  *
  830.  */
  831.  
  832.  
  833.